#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

#include <vector>
#include <atomic>
#include <mutex>
#include <stdarg.h>
#include <functional>
#include <unordered_map>
#include "sink.hpp"
#include "LogMessage.hpp"
#include "Level.hpp"
#include "OutFormat.hpp"
#include "AsyncWorker.hpp"

/*
    日志器模块:
        功能:对前边所有模块进行整合，向外提供接口完成不同等级日志的输出
*/

namespace log
{
    class logger
    {
    public:
        enum class Type
        {
            LOGGER_SYNCH, // 同步
            LOGGER_ASYNCH // 异步
        };

    public:
        using ptr = std::shared_ptr<logger>;
        logger(std::string LoggerName, log::Format::ptr Format, log::LogLevel::Level level, std::vector<log::Sink::ptr> &Sinks)
            : _LoggerName(LoggerName), _Format(Format), _Level(level), _Sinks(Sinks.begin(), Sinks.end())
        {
        }
        std::string GetLoggerName() { return _LoggerName.c_str(); }
        log::LogLevel::Level GetLevel() { return _Level; }

        void Debug(const char *fileName, size_t line, const char *fmt, ...)
        {
            if (_Level > log::LogLevel::Level::DEBUG)
                return; // Debug等级大于等于限制等级,就可以输出
            va_list va;
            va_start(va, fmt);
            log(log::LogLevel::Level::DEBUG, fileName, line, fmt, va);
            va_end(va);
        }

        void Info(const char *fileName, size_t line, const char *fmt, ...)
        {
            if (_Level > log::LogLevel::Level::INFO)
                return; // Debug等级大于等于限制等级,就可以输出
            va_list va;
            va_start(va, fmt);
            log(log::LogLevel::Level::INFO, fileName, line, fmt, va);
            va_end(va);
        }

        void Warning(const char *fileName, size_t line, const char *fmt, ...)
        {
            if (_Level > log::LogLevel::Level::WARNING)
                return;
            va_list va;
            va_start(va, fmt);
            log(log::LogLevel::Level::WARNING, fileName, line, fmt, va);
            va_end(va);
        }

        void Error(const char *fileName, size_t line, const char *fmt, ...)
        {
            if (_Level > log::LogLevel::Level::ERROR)
                return;
            va_list va;
            va_start(va, fmt);
            log(log::LogLevel::Level::ERROR, fileName, line, fmt, va);
            va_end(va);
        }

        void Fatal(const char *fileName, size_t line, const char *fmt, ...)
        {
            if (_Level > log::LogLevel::Level::FATAL)
                return;
            va_list va;
            va_start(va, fmt);
            log(log::LogLevel::Level::FATAL, fileName, line, fmt, va);
            va_end(va);
        }

    public:
        class BuliderLogger // 局部建造者,建造需要的变量参数
        {
        public:
            using ptr = std::shared_ptr<BuliderLogger>;
            BuliderLogger()
                : _type(log::logger::Type::LOGGER_SYNCH) // 默认同步输出和Debug输出等级
                  ,
                  _Level(log::LogLevel::Level::DEBUG)
            {
            }

            void BuilderLoggerName(const std::string LoggerName) { _LoggerName = LoggerName; }

            void BuilderFormat(const std::string pattern) { _Format = std::make_shared<log::Format>(pattern); } // 传格式化字符,让该建造者去创建

            void BuilderFormat(const log::Format::ptr &Format) { _Format = Format; }

            void BuilderType(log::logger::Type type) { _type = type; }

            void Build_AsyncWorker_UnSafeType() { _Asynctype = AsyncType::ASYNC_UNSAFE; } // 设置为非安全模式,默认是安全模式

            void BuilderLevel(log::LogLevel::Level Lever) { _Level = Lever; }

            template <typename SinkType, typename... Args>
            void BuilderSinks(Args &&...args)
            {
                log::Sink::ptr sink = std::make_shared<SinkType>(args...);
                _Sinks.push_back(sink);
            }

            virtual logger::ptr Build() = 0;

        protected:
            std::string _LoggerName;            // 日志器名称
            log::Format::ptr _Format;           // 日志的格式化输出
            log::logger::Type _type;            // 同步或者异步输出
            log::LogLevel::Level _Level;        // 日志输出限制等级
            std::vector<log::Sink::ptr> _Sinks; // 日志的落地方向,一个日志器可能向多个方向进行日志输出
            AsyncType _Asynctype;               // 日志工作器的安全模式
        };

    protected:
        void log(log::LogLevel::Level Level, const char *filename, size_t line, const char *fmt, va_list va)
        {
            std::string message;
            char *buf;
            int len = vasprintf(&buf, fmt, va);
            if (len < 0)
            {
                std::cerr << "格式化消息失败" << std::endl;
            }
            else
            {
                message.assign(buf, len); // 用c字符串去string类型赋值
                free(buf);
            }
            log::LogMessage logs(filename, line, message, Level, _LoggerName);
            std::stringstream ss;
            _Format->format(ss, logs); // 将日志信息打印为字符串
            logIt(ss.str());           // 信息交给函数去处理
        }
        virtual void logIt(const std::string &logs) = 0; // 不同的日志器有不同的落地方式,在同步日志器和异步日志器进行重新定义

    protected:
        std::string _LoggerName;                  // 日志器名称
        std::mutex _mutex;                        // 锁用来保证日志的输出是线程安全的
        log::Format::ptr _Format;                 // 日志的格式化输出
        std::atomic<log::LogLevel::Level> _Level; // 日志输出限制等级
        std::vector<log::Sink::ptr> _Sinks;       // 日志的落地方向,一个日志器可能向多个方向进行日志输出
    };
    class SyncLogger : public logger
    {
    public:
        SyncLogger(std::string &name, log::Format::ptr &Format, log::LogLevel::Level &Level, std::vector<log::Sink::ptr> &Sinks)
            : logger(name, Format, Level, Sinks)
        {
            std::cout << "同步日志器" << name << "创建成功" << std::endl;
        }
        virtual void logIt(const std::string &logs) // 处理数据
        {
            if (_Sinks.empty())
                return; // 落地方式是空,就退出
            {
                std::unique_lock<std::mutex> lock(_mutex); // 加锁
                for (auto &it : _Sinks)
                {
                    it->log(logs.c_str(), logs.size());
                }
            }
        }
    };
    class AsyncLogger : public logger
    {
    public:
        AsyncLogger(std::string &name, log::Format::ptr &Format, log::LogLevel::Level &Level, std::vector<log::Sink::ptr> &Sinks, AsyncType &type)
            : logger(name, Format, Level, Sinks), _looper(std::make_shared<AsyncWorker>(std::bind(&AsyncLogger::RealLog, this, std::placeholders::_1)))
        {
            std::cout << "异步日志器" << name << "创建成功" << std::endl;
            if (type == AsyncType::ASYNC_UNSAFE) // 设置非安全模式
                _looper->SetUnSafe();
        }

    protected:
        virtual void logIt(const std::string &logs) // 处理数据
        {
            _looper->push(logs.c_str(), logs.size());
        }
        void RealLog(Buffer &buffer)
        {
            if (_Sinks.empty())
                return; // 落地方式是空,就退出

            for (auto &it : _Sinks)
            {
                it->log(buffer.begin(), buffer.ReadAble());
            }
        }

    protected:
        AsyncWorker::ptr _looper; // 异步工作器
    };
    class LocalBuildLogger : public logger::BuliderLogger // 本地建造者,主要实现局部建造者建造完毕,检测有没有建造完成和判断是同步日志器还是异步日志器。
    {
    public:
        virtual logger::ptr Build() // 注意Build是其他变量赋值后再进行修改的
        {
            if (_LoggerName.empty())
            {
                std::cerr << "日志器的名称不能为空" << std::endl;
                abort();
            }
            if (_Format.get() == nullptr) // 注意get函数是智能指针里面的
            {
                std::cout << "当前日志器" << _LoggerName;
                std::cout << "未检测到日志输出格式";
                std::cout << "默认输出格式是[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n" << std::endl;
                _Format = std::make_shared<log::Format>();
            }
            if (_Sinks.empty())
            {
                std::cout << "当前日志器" << _LoggerName;
                std::cout << "未确定落地方向";
                std::cout << "默认日志器落地方向是stdout" << std::endl;
                _Sinks.push_back(std::make_shared<log::Stdoutsink>());
            }
            logger::ptr lp;
            if (_type == log::logger::Type::LOGGER_SYNCH) // 同步日志器
            {
                lp = std::make_shared<SyncLogger>(_LoggerName, _Format, _Level, _Sinks);
            }
            else // 异步日志器
            {
                lp = std::make_shared<AsyncLogger>(_LoggerName, _Format, _Level, _Sinks, _Asynctype); // 传多一个参数,表示安全模式或者非安全模式
            }

            return lp;
        }
    };
    class loggermanager // 日志器管理器
    {
    private:
        loggermanager()
        {
            std::shared_ptr<LocalBuildLogger> localBuild(new LocalBuildLogger()); // 使用本地建造者建造一个主日志器,默认往标准输出进行输出
            localBuild->BuilderLoggerName("root_logger");
            localBuild->BuilderType(logger::Type::LOGGER_SYNCH); // 同步
            _root_logger = localBuild->Build();                  // 建造
            _loggers.insert(std::make_pair("root_logger", _root_logger));        // 添加进去
        }
        loggermanager(const loggermanager &) = delete;
        loggermanager &operator=(const loggermanager &) = delete;

    public:
        static loggermanager& GetInstance() // 返回单例
        {
            static loggermanager lm; // c++11以后,静态局部变量的创建是线程安全的
            return lm;               //当建造静态局部变量,其他线程进入就会阻塞
        }
        void Addlogger(const std::string &name, logger::ptr &logger) // 添加日志器
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(name, logger));
        }
        bool Haslogger(const std::string &name) // 判断日志器是否存在
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }
        logger::ptr GetLogger(const std::string &name) // 获取日志器
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return logger::ptr(); // 构造空指针,返回
            }
            return it->second;
        }
        logger::ptr root_logger() // 返回主日志器
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _root_logger;
        }

    private:
        std::mutex _mutex;                                // 锁,保护临界资源_loggers
        logger::ptr _root_logger;                         // 默认日志器,往标准输出输出
        std::unordered_map<std::string, logger::ptr> _loggers; // 日志器
    };
    class GlobalBuildLogger : public logger::BuliderLogger // 全局建造者,为日志管理器服务
    {
    public:
        virtual logger::ptr Build() // 注意Build是其他变量赋值后再进行修改的
        {
            if (_LoggerName.empty())
            {
                std::cerr << "日志器的名称不能为空" << std::endl;
                abort();
            }
            if (_Format.get() == nullptr) // 注意get函数是智能指针里面的
            {
                std::cout << "当前日志器" << _LoggerName;
                std::cout << "未检测到日志输出格式";
                std::cout << "默认输出格式是[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n" << std::endl;
                _Format = std::make_shared<log::Format>();
            }
            if (_Sinks.empty())
            {
                std::cout << "当前日志器" << _LoggerName;
                std::cout << "未确定落地方向";
                std::cout << "默认日志器落地方向是stdout" << std::endl;
                _Sinks.push_back(std::make_shared<log::Stdoutsink>());
            }
            logger::ptr lp;
            if (_type == log::logger::Type::LOGGER_SYNCH) // 同步日志器
            {
                lp = std::make_shared<SyncLogger>(_LoggerName, _Format, _Level, _Sinks);
            }
            else // 异步日志器
            {
                lp = std::make_shared<AsyncLogger>(_LoggerName, _Format, _Level, _Sinks, _Asynctype); // 传多一个参数,表示安全模式或者非安全模式
            }

            loggermanager::GetInstance().Addlogger(_LoggerName,lp);//添加日志器
            
            return lp;
        }
    };
}

#endif


